/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package engine.linkList;
import engine.player.MusicPlayer;
import java.io.*;
import java.util.Random;
/**
 *
 * @author hjp
 */


/**
 * 播放调度管理模块，采用副本算法，
 * 其功能是，根据用户操作，将指向当前播放音乐结点的指针指向正确的位置
 * 播发调度器不负责更新与维护播放器中的链表，比如播放链表；
 * 播放调度器所管理的指针，有2类：
 * 1.指向LinkedListManager中的某张链表
 * 2.指向副本链表的指针
 * 播放调度器内部的副本链表在生成之后并不需要进行管理。
 */
public class PlayScheduleManager implements Serializable {
    private static final long serialVersionUID = -169464833959039135L;

    /**
     * 当前播放的歌单所在的歌单集合
     * 当且仅当播放器曾经播放过某首歌曲且该歌曲所在的歌单没有被删除，currentPlayMusicLists才非空
     */
    MusicLists currentPlayMusicLists;//初始化的时候需要知道它指向谁

    /**
    当前播放的歌单
    它永远指向LinkedListManager中的某张存在的链表。
     当且仅当播放器曾经播放过某首歌曲且该歌曲所在的歌单没有被删除，currentPlayMusicList才非空,
     且从歌单中删除某首歌曲的算法机制保证了，此时currentPlayMusicList里面的歌曲数目也必不为0
     */
    public Node<MusicListNode> currentPlayMusicList;//初始化的时候需要知道它指向谁

    /**
     * 当前播放模式
     */
    PlayMode currentMode;//需要被序列化

    /**
     * 指向pCurrentPlayMusicList中的当前播放乐曲
     */
    public Node<MusicNode> pCurrentPlayMusicNodeCopy;//初始化的时候需要知道它指向谁

    /**
     * 指向用户选择的播放列表的某个副本
     * P.S.只有在playImmediately方法中用户才可以更改当前播放歌单
     */
    transient Node<MusicListNode> pCurrentPlayMusicListCopy;//不需要序列化存储。初始化的时候根据currentMode以初始化指向

    /**
    以下是指向副本链表的引用
     */
    transient Node<MusicListNode> musicListCopy;//不需要被序列化。播放器启动的时候根据currentPlayMusicList初始化
    transient Node<MusicListNode> musicListCopyRandom;//不需要序列化存储。播放器启动的时候根据currentPlayMusicList初始化


    /**
     * 单例模式
     */
    static PlayScheduleManager manager = new PlayScheduleManager();

    /**
     * 单例模式
     */
    public static PlayScheduleManager getInstance(){
        return manager;
    }


    private PlayScheduleManager(){
    }
    
    public PlayMode getCurrentMode(){
        return currentMode;
    }


    /**立即播放某首歌曲.所选择的立即播放的歌曲必然在currentVisitMusicList中.
     *当用户双击GUI中的某首歌曲播放时调用
     * 注意：1.立即播放某首歌曲操作可能导致副本播放链表的更换.
     *      2.调用该算法的机制保证了，能够调用该方法的时候，
     *      currentVisitMusicList必不为空，且里面的歌曲数目也必不为0
     */
    public void playImmediately(Node<MusicNode> selectedMusicNode){
        /*
        如果立即播放的歌曲所在歌单与当前播放歌单原件不同，或者
        立即播放的歌曲所在歌单就是当前正在播放的歌单（原件），但是
        原件已被修改或者副本已被修改，
        则都需要重新初始化副本链表
         */
        if (LinkedListManager.manager.currentVisitMusicList != currentPlayMusicList ||
                (currentPlayMusicList.info.isModify || pCurrentPlayMusicListCopy.info.isModify)){
            //删除原来的副本链表
            deleteCopyList();
            //下面创建副本链表
            musicListCopy = createSequenceMusicList(LinkedListManager.manager.currentVisitMusicList);
            musicListCopyRandom = createRandomMusicList(LinkedListManager.manager.currentVisitMusicList);
            //根据当前播放模式，将当前播放的副本链表的指针正确置位
            switch (currentMode){
                case SEQUENCE:
                case SINGLE_CYCLE: {
                    pCurrentPlayMusicListCopy = musicListCopy;
                    break;
                }
                case RANDOM:{
                    pCurrentPlayMusicListCopy = musicListCopyRandom;
                    break;
                }
            }
            //如果立即播放的歌曲所在歌单与当前播放歌单原件不同，则修改当前播放歌单
            if (LinkedListManager.manager.currentVisitMusicList != currentPlayMusicList){
                currentPlayMusicList = LinkedListManager.manager.currentVisitMusicList;
                currentPlayMusicLists = LinkedListManager.manager.currentVisitMusicLists;
            }
        }
        //机制保证，此时pCurrentPlayMusicNodeCopy必不为空
        pCurrentPlayMusicNodeCopy = findSelectedMusicNode(selectedMusicNode);
        MusicPlayer.musicPlayer.playMp3FileImmediately(pCurrentPlayMusicNodeCopy.info.filePath);
    }

    /**
     * 设定播放模式
     */
    public void setPlayMode(PlayMode mode){
        //currentPlayMusicList != null时，除循环副本链表之外的副本链表必不为空,
        // 故pCurrentPlayMusicNodeCopy和pCurrentPlayMusicListCopy必不为空
        if (mode != currentMode && currentPlayMusicList != null){
            switch (mode){
                case SEQUENCE:
                case SINGLE_CYCLE:{
                    pCurrentPlayMusicListCopy = musicListCopy;
                    Node<MusicNode> p = findSelectedMusicNode(pCurrentPlayMusicNodeCopy);
                    if (p != null){
                        pCurrentPlayMusicNodeCopy = p;
                    }
                    else {
                        /*
                        此时，意味着当前播放的音乐在顺序链表中不存在
                        可能是因为这首歌曲是从其他播放链表中插入到上一个播放模式下的链表的
                        此时将当前播放歌曲结点复制一份，然后再随便插入到顺序播放链表中的某个结点之后（或之前)
                        */
                        p = new Node<>(pCurrentPlayMusicNodeCopy.info);//复制
                        pCurrentPlayMusicNodeCopy = p;
                        Random random = new Random(System.nanoTime());
                        int index = random.nextInt(pCurrentPlayMusicListCopy.info.sum);
                        Node<MusicNode> q = pCurrentPlayMusicListCopy.info.head;
                        while(index != 0){
                            q = q.next;
                            --index;
                        }
                        if (q.next != null){
                            q.addNext(pCurrentPlayMusicNodeCopy);
                        }
                        else {
                            q.addNext(pCurrentPlayMusicNodeCopy);
                            pCurrentPlayMusicListCopy.info.tail = pCurrentPlayMusicNodeCopy;
                        }
                        pCurrentPlayMusicListCopy.info.isModify = true;
                        pCurrentPlayMusicListCopy.info.sum++;
                    }
                    break;
                }
                case RANDOM:{
                    pCurrentPlayMusicListCopy = musicListCopyRandom;
                    Node<MusicNode> p = findSelectedMusicNode(pCurrentPlayMusicNodeCopy);
                    if (p != null){
                        pCurrentPlayMusicNodeCopy = p;
                    }
                    else {
                        p = new Node<>(pCurrentPlayMusicNodeCopy.info);
                        pCurrentPlayMusicNodeCopy = p;
                        pCurrentPlayMusicListCopy.info.addHead(pCurrentPlayMusicNodeCopy);
                    }
                    break;
                }
            }
            currentMode = mode;
        }
    }


    /**
     * 插歌算法
     */
    public void setNextPlay(Node<MusicNode> musicNode){
        //如果被选中的歌曲所在歌单不是当前播放歌单的话，直接插入到当前播放链表中来
        if (LinkedListManager.manager.currentVisitMusicList != currentPlayMusicList){
            Node<MusicNode> newNode = new Node<>(musicNode.info);
            if (pCurrentPlayMusicNodeCopy.next != null){
                pCurrentPlayMusicNodeCopy.addNext(newNode);
            }
            else {
                pCurrentPlayMusicNodeCopy.addNext(newNode);
                pCurrentPlayMusicListCopy.info.tail = newNode;
            }
        }
        //如果被选中的歌曲所在歌单是当前播放歌单,则检索被选定的歌曲是否在当前播放的副本链表内
        else {
            Node<MusicNode> p = findSelectedMusicNode(musicNode);
            if (p != null){
                p.next.pre = p.pre;
                p.pre.next = p.next;
                p.next = null;
                p.pre = null;
                if (pCurrentPlayMusicNodeCopy.next != null){
                    pCurrentPlayMusicNodeCopy.addNext(p);
                }
                else {
                    pCurrentPlayMusicNodeCopy.addNext(p);
                    pCurrentPlayMusicListCopy.info.tail = p;
                }
            }
            else {
                Node<MusicNode> newNode = new Node<>(musicNode.info);
                if (pCurrentPlayMusicNodeCopy.next != null){
                    pCurrentPlayMusicNodeCopy.addNext(newNode);
                }
                else {
                    pCurrentPlayMusicNodeCopy.addNext(newNode);
                    pCurrentPlayMusicListCopy.info.tail = newNode;
                }
            }
        }
        //置修改位
        pCurrentPlayMusicListCopy.info.isModify = true;
    }


    /**
     * 非默认的播放下一首操作将根据当前播放模式，在对应的副本链表找到下一首。
     * 非默认的操作将由系统自动调用
     */
    public Node<MusicNode> getNextPlay(){
        if (currentMode != PlayMode.SINGLE_CYCLE){
            return getNextPlayDefault();
        }
        else {
            return pCurrentPlayMusicNodeCopy;
        }
    }

    /**
     * 非默认的播放上一首操作将根据当前播放模式，在对应的播放链表中找到上一首
     * 非默认的操作将由系统自动调用
     */
    public Node<MusicNode> getPrePlay(){
        if (currentMode != PlayMode.SINGLE_CYCLE){
            return getPrePlayDefault();
        }
        else {
            return pCurrentPlayMusicNodeCopy;
        }
    }


    /**
     * 默认的播放下一首操作将无视当前播放模式，仅在当前播放副本链表中找到下一首
     * 仅由用户调用
     */
    public Node<MusicNode> getNextPlayDefault(){
        if (pCurrentPlayMusicNodeCopy != null && pCurrentPlayMusicListCopy != null){
            Node<MusicNode> p = pCurrentPlayMusicNodeCopy.next;
            //实现列表循环
            if (p != null){
                pCurrentPlayMusicNodeCopy = p;
                return p;
            }
            else{
                pCurrentPlayMusicNodeCopy = pCurrentPlayMusicListCopy.info.head;
                return pCurrentPlayMusicListCopy.info.head;
            }
        }
        return null;
    }

    /**
     * 默认的播放上一首操作将无视当前播放模式，仅在当前播放副本链表中找到上一首
     * 仅由用户调用
     */
    public Node<MusicNode> getPrePlayDefault(){
        if (pCurrentPlayMusicNodeCopy != null && pCurrentPlayMusicListCopy != null){
            Node<MusicNode> p = pCurrentPlayMusicNodeCopy.pre;
            //实现列表循环
            if (p != null){
                pCurrentPlayMusicNodeCopy = p;
                return p;
            }
            else{
                pCurrentPlayMusicNodeCopy = pCurrentPlayMusicListCopy.info.tail;
                return pCurrentPlayMusicListCopy.info.tail;
            }
        }
        return null;
    }

     /*
    以下是3种播放模式的实现
     */

    /**
     * 创建顺序播放歌单
     */
    Node<MusicListNode> createSequenceMusicList(Node<MusicListNode> musicListNode){
        if (musicListNode != null){
            MusicListNode newList = new MusicListNode();
            Node<MusicNode> p = musicListNode.info.head;//用于遍历待拷贝链表
            Node<MusicNode> newNode;
            while(p != null){
                newNode = new Node<>(p.info);
                newList.addTail(newNode);
                p = p.next;
            }
            newList.isModify = false;
            return new Node<>(newList);
        }
        else {
            return null;
        }
    }

    /**
     * 创建随机播放歌单
     */
    Node<MusicListNode> createRandomMusicList(Node<MusicListNode> musicListNode){
        if (musicListNode != null){
            //musicListNode至少有一首歌曲
            MusicListNode newList = new MusicListNode();
            newList.addTail(new Node<>(musicListNode.info.head.info));
            Node<MusicNode> pOrigin = musicListNode.info.head.next;//用于遍历待拷贝链表
            Node<MusicNode> pCopy;//用于遍历newList
            Node<MusicNode> newNode;
            Random random = new Random(System.nanoTime());
            int index;
            while(pOrigin != null){
                newNode = new Node<>(pOrigin.info);
                index = random.nextInt(newList.sum);
                pCopy = newList.head;
                while(index != 0){
                    pCopy = pCopy.next;
                    --index;
                }
                if (pCopy.next != null){
                    pCopy.addNext(newNode);
                }
                else {
                    pCopy.addNext(newNode);
                    newList.tail = newNode;
                }
                newList.sum++;
                pOrigin = pOrigin.next;
            }
            newList.isModify = false;
            return new Node<>(newList);
        }
        else {
            return null;
        }
    }

    /**
     * 在当前播放的副本链表中找到指定的音乐结点
     */
    public Node<MusicNode> findSelectedMusicNode(Node<MusicNode> musicNode){
        if (pCurrentPlayMusicListCopy != null && musicNode != null && musicNode.info != null){
            Node<MusicNode> p = pCurrentPlayMusicListCopy.info.head;
            while (p != null){
                if (musicNode.info.equal(p.info)){
                    return p;
                }
                p = p.next;
            }
            return null;
        }
        else {
            return null;
        }
    }

    /**
     * 删除CopyList
     */
    private void deleteCopyList(){
        //删除musicListCopy
        if (musicListCopy != null && musicListCopy.info != null){
            musicListCopy.info.delete();
            musicListCopy.delete();
        }
        //删除musicListCopyRandom
        if (musicListCopyRandom != null && musicListCopyRandom.info != null){
            musicListCopyRandom.info.delete();
            musicListCopyRandom.delete();
        }
        musicListCopy = musicListCopyRandom = null;
    }
}

